﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Tools.Maptools.Editor
{

#if UNITY_EDITOR
    [ExecuteInEditMode]
    // 道路编辑器 生成的道路对象脚本
    public class SandBoxRoadInfo : MonoBehaviour
    {
        [Tooltip("道路id")]
        public int road_id = -1;
        string name = "";
        [Tooltip("道路路点集合")]
        public List<GameObject> map_points = new List<GameObject>();

        [Tooltip("道路选中 true 移动道路移动所有路点")]
        public bool b_road_select;
        public Vector3 v3_last_pos;//道路位置

        [Tooltip("需要检查衔接点的道路线段起点")]
        public GameObject road_check;
        public List<int> check_idxs = new List<int>();
        float f_last_angle = 0;
        float f_start_angle = 0;
        public LineRenderer render;
        LineMeshCreater mesh_creater;
        public GameObject obj_center;
        public string s_road_type = "";
        public bool broad = true;

        Vector3 v3_min;
        Vector3 v3_max;
        bool b_init_pos = false;
        Vector3 v3_cross_start_pos;// 记录衔接点的相对中心点位置

        // 路灯
        List<SandBoxRoadInfo> road_lights = new List<SandBoxRoadInfo>();
        int light_sum_id = 0;   // 路灯id = 道路id * 10000 + light_sum_id
        GameObject obj_light;   // 路灯预制体
        float light_space;

        public float roadWidth = 0;
        private float m_lastRoadWidth = 0;
        // 贝塞尔
        [Serializable]
        public struct BezierPoints {
            public GameObject bezier_start;
            public GameObject bezier_end;
            public GameObject bezier_control0;
            public GameObject bezier_control1;
            [HideInInspector]
            public int start_idx;
            [HideInInspector]
            public int end_idx;
            [Tooltip("曲线插入点数量 越多越平滑")]
            public int bezier_point_num;

            public bool CheckContainPoint(GameObject point)
            {
                if (bezier_start.transform.GetSiblingIndex() > bezier_end.transform.GetSiblingIndex())
                {
                    GameObject temp = bezier_start;
                    bezier_start = bezier_end;
                    bezier_end = bezier_start;
                }
                return bezier_start == point;
            }
        }
        [Tooltip("贝塞尔控件弯道点集合 注意弯道间不能有重合")]
        public List<BezierPoints> list_bezier_points = new List<BezierPoints>();

        [HideInInspector]
        public bool b_bezier_update = false;

        private GameObject bezier_control_root;
        private List<Vector3> bezier_control_temp = new List<Vector3>();
        #region 初始化

        public void InitRoad(int roadId,int count,string road_type,GameObject obj_light = null,float light_space = 0)
        {
            road_id = roadId;
            s_road_type = road_type;
            broad = !(road_type.Contains("Cross") || road_type.Contains("bridge"));// 名字没有cross就是路 之后修改
            if (broad)
            {
                render = gameObject.GetComponent<LineRenderer>();
                render.positionCount = count;
                mesh_creater = gameObject.transform.GetChild(0).GetComponent<LineMeshCreater>();
                mesh_creater.gameObject.layer = 20;

            }
            else
            {
                v3_cross_start_pos = Vector3.zero;
            }
            // 
            obj_center = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            Collider c = obj_center.GetComponent<Collider>();
            if (c != null) c.enabled = false;
            obj_center.name = "center";
            obj_center.transform.localScale = Vector3.one;
            obj_center.transform.parent = transform;
            obj_center.transform.localPosition = Vector3.zero;
            this.obj_light = obj_light;
            this.light_space = light_space;
        }

        public void UpdateRoad(Material mat, float width)
        {
            if (render && broad)
            {
                render.sharedMaterial = mat;
                render.startWidth = width;
                render.endWidth = width;
                roadWidth = width;
                m_lastRoadWidth = width;
            }
        }

        #endregion

        #region 设置路点(道路才使用)

        public void CreatePoint()
        {
            Vector3[] points = GetRoadPointList();
            int count = points.Length;
            GameObject obj_point = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            obj_point.name = gameObject.name + "_road_" + count;
            //obj_point.tag = "road_point";
            obj_point.transform.localPosition = points[count - 1] + new Vector3(1,0,1);
            obj_point.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
            map_points.Add(obj_point);
            obj_point.transform.parent = transform;
            obj_point.SetActive(false);
            SandBoxRoadPoint s = obj_point.AddComponent<SandBoxRoadPoint>();
            s.InitPoint(this, count);
            CheckMinMaxPos(obj_point.transform.localPosition);
            render.positionCount = map_points.Count;
            render.SetPositions(GetRoadPointList());
            UpdateRoadMesh();
        }

        public void SetRoadPoint(int idx,Vector3 point)
        {
            if (!broad) return;
            point.y = 0;// 所有的路点y轴一定是0
            render.SetPosition(idx, point);
            GameObject obj_point = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            obj_point.name = gameObject.name + "_road_" + idx;
            //obj_point.tag = "road_point";
            obj_point.transform.localPosition = point;
            obj_point.transform.localScale =   new Vector3(0.1f, 0.1f, 0.1f);
            map_points.Add(obj_point);
            obj_point.transform.parent = transform;
            obj_point.SetActive(false);
            SandBoxRoadPoint s = obj_point.AddComponent<SandBoxRoadPoint>();
            s.InitPoint(this, idx);
            CheckMinMaxPos(point);
        }

        public void RemovePoint(int idx)
        {
            if (!broad) return;
            map_points.RemoveAt(idx);
            render.positionCount = map_points.Count;
            render.SetPositions(GetRoadPointList());
            UpdateRoadMesh();
        }
        public void UpdateRoadPoint(int idx, Vector3 point)
        {
            if (!broad) return;
            render.SetPosition(idx, new Vector3(point.x,0,point.y));
   
            UpdateRoadMesh();
        }

        public void SetPointInLine()
        {
            if (!broad) return;
            for (int i = 0;i < map_points.Count;i++)
            {
                if (i == 0)
                {
                    continue;
                }
                else if (i == map_points.Count - 1)
                {
                    GameObject obj0 = map_points[0];
                    GameObject obj1 = map_points[map_points.Count - 1];
                    Vector3 v30 = obj0.transform.position;
                    Vector3 v31 = obj1.transform.position;
                    float dis = (v31 - v30).magnitude;
                    float a = obj_center.transform.eulerAngles.y;
                    v31 = v30 + new Vector3(dis * Mathf.Cos(a * 180 / Mathf.PI), 0, dis * Mathf.Sin(a * 180 / Mathf.PI));
                    obj1.transform.position = v31;

                    render.positionCount = 2;
                    render.SetPositions(GetRoadPointList());
                    UpdateRoadMesh();
                }
                else
                {
                    SandBoxRoadPoint point = map_points[i].GetComponent<SandBoxRoadPoint>();
                    point.bRemove = false;
                    map_points.RemoveAt(i);
                    DestroyImmediate(point.gameObject);
                }
            }
        }

        public void SetCheckCrossPoint()
        {
            if (road_check)
            {
                int idx = GetChildIdx(road_check.transform.parent, road_check.transform) - 2;
                if (idx >= 0 && check_idxs.Contains(idx) == false)
                {
                    check_idxs.Add(idx);
                }
            }
        }
        public void SetCheckCrossPoints(string points)
        {
            var datas = points.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0;i < datas.Length;i++)
            {
                int idx = -1;
                int.TryParse(datas[i], out idx);
                if (idx >= 0)
                {
                    check_idxs.Add(idx);
                }
            }
        }
        public string GetCheckCrossPoints()
        {
            string points = "";
            for (int i = 0;i < check_idxs.Count;i++)
            {
                points += check_idxs[i].ToString() + "|";
            }
            return points;
        }
        #endregion

        #region 更新

        public void UpdateRoadMesh()
        {
            if (!broad) return;
            Vector3[] points = GetRoadPointList();
            //mesh_creater.transform.position = Vector3.zero;
            Mesh m = mesh_creater.GetMesh(points, render.startWidth, Vector3.up);
            Vector3 v3_center = Vector3.zero;
            for (int i = 0;i < points.Length; i++)
            {
                v3_center += points[i];
            }
            v3_center = v3_center / points.Length;
            obj_center.transform.position = v3_center;
            v3_last_pos = v3_center;
        }

        void CheckMinMaxPos(Vector3 pos)
        {
            if (!b_init_pos)
            {
                v3_min = pos;
            }
            else
            {
                if (pos.x < v3_min.x)
                {
                    v3_min.x = pos.x;
                }
                if (pos.z < v3_min.z)
                {
                    v3_min.z = pos.z;
                }
            }
            if (!b_init_pos)
            {
                v3_max = pos;
            }
            else
            {
                if (pos.x > v3_max.x)
                {
                    v3_max.x = pos.x;
                }
                if (pos.z > v3_max.z)
                {
                    v3_max.z = pos.z;
                }
            }
            b_init_pos = true;
        }

        public Vector3 GetMinPos()
        {
            if (broad)
            {
                return v3_min;
            }
            else
            {
                return transform.position;
            }
        }
        public Vector3 GetMaxPos()
        {
            if (broad)
            {
                return v3_max;
            }
            else
            {
                return transform.position;
            }
        }

        #endregion

        #region 路灯

        public void AddLight()
        {


        }

        public void RemoveLight()
        { 
        
        }

        #endregion

        #region 其他

        public string GetRoadType()
        {
            return s_road_type;
        }

        public string GetRoadPoints()
        {
            string res = "";
            if (broad)
            {
                foreach (var obj in map_points)
                {
                    if (obj)
                    {
                        Vector3 pos = obj.transform.position;
                        res += string.Format("{0}_{1}|", pos.x, pos.z);
                    }
                }
            }
            else
            {
                Vector3 pos = transform.position;
                res += string.Format("{0}_{1}|", pos.x, pos.z);
            }
         
            return res;
        }
        public Vector3[] GetRoadPointList()
        {
            List<Vector3> positions = new List<Vector3>();
            if (broad)
            {
                foreach (var obj in map_points)
                {
                    if (obj)
                    {
                        positions.Add(obj.transform.position);
                    }
                }
            }
            else
            {
                positions.Add(transform.position);
            }
         
            return positions.ToArray();
        }

        public void PointRotate(Vector3 origin, ref Vector3 rePoint, float angle)
        {
            float cos = Mathf.Cos(angle);
            float sin = Mathf.Sin(angle);
            float x = (rePoint.x - origin.x) * cos - (rePoint.z - origin.z) * sin + origin.x;
            float z = (rePoint.x - origin.x) * sin + (rePoint.z - origin.z) * cos + origin.z;

            rePoint.x = x;
            rePoint.z = z;
        }
        public void RoadRotate(float _angle,Vector3 origin)
        {
            f_last_angle = obj_center.transform.eulerAngles.y; ;
            if (broad)
            {
                foreach (var obj in map_points)
                {
                    SandBoxRoadPoint point = obj.GetComponent<SandBoxRoadPoint>();
                    Vector3 pos = point.start_pos + origin;
                    PointRotate(origin, ref pos, _angle * Mathf.Deg2Rad);
                    obj.transform.position = pos;
                }
                render.SetPositions(GetRoadPointList());
                UpdateRoadMesh();
            }
            else
            {
                Vector3 pos = v3_cross_start_pos + origin;
                PointRotate(origin, ref pos, _angle * Mathf.Deg2Rad);
                transform.position = pos;

                Vector3 e = transform.eulerAngles;
                e.y = _angle;
                transform.eulerAngles = e;
            }
           
        }
        public void RoadMove(Vector3 dis)
        {
            dis.y = 0;
            if (broad)
            {
                v3_last_pos = v3_last_pos + dis;
                List<Vector3> positions = new List<Vector3>();
                foreach (var obj in map_points)
                {
                    obj.transform.position += dis;
                    SandBoxRoadPoint point = obj.GetComponent<SandBoxRoadPoint>();
                    //point.start_pos = obj.transform.position - obj_center.transform.position;
                    positions.Add(obj.transform.position);
                }
                render.SetPositions(positions.ToArray());
                UpdateRoadMesh();
                obj_center.transform.position = v3_last_pos;
            }
            else
            {
                transform.position += dis;
                //v3_start_pos = transform.position;
                obj_center.transform.position = transform.position;
            }
        }

        public void SetOrigin(Vector3 center)
        {
            if (broad)
            {
                foreach (var obj in map_points)
                {
                    SandBoxRoadPoint point = obj.GetComponent<SandBoxRoadPoint>();
                    point.start_pos = obj.transform.position - center;
                }
            }
            else
            {
                v3_cross_start_pos = transform.position - center;
            }
        }

        int GetChildIdx(Transform p, Transform self)
        {
            int idx = -1;
            if (p != null && self != null)
            {
                for (int i = 0;i < p.childCount; i++)
                {
                    Transform t = p.GetChild(i);
                    if (t == self)
                    {
                        idx = i;
                        break;
                    }
                }
            }
            return idx;
        }

        #endregion

        #region 贝塞尔

        public void SetBezierPoint()
        {
            if (list_bezier_points.Count <= 0)
            {
                Debug.LogError("[道路编辑器] 贝塞尔曲线没有设置任何一段控制曲线 逗我玩呢");
            }
            else
            {
                if (b_bezier_update)
                {
                    // 开启贝塞尔曲线设置
                    StartBezier();
                }
                else
                {
                    // 关闭贝塞尔曲线设置
                    EndBezier();
                }
            }
        }

        private void StartBezier()
        {
            List<Vector3> points = new List<Vector3>(); // 新生成的路点 

            if (bezier_control_root == null)
            {
                bezier_control_root = new GameObject();
                bezier_control_root.transform.position = Vector3.zero;
            }
            for (int i = 2; i < transform.childCount;) // 从第二个开始才是路点
            {
                Transform point = transform.GetChild(i);
                bool b_insert = false;
                for (int ii = 0; ii < list_bezier_points.Count; ii++)
                {
                    var bezier_info = list_bezier_points[ii];
                    if (bezier_info.CheckContainPoint(point.gameObject))
                    {
                        b_insert = true;
                        // 向points中填充 start 的数据
                        bezier_info.start_idx = points.Count;
                        points.Add(bezier_info.bezier_start.transform.position);
                        // 向points中填充 start - end 的数据
                        for (int iii = 0;iii < bezier_info.bezier_point_num;iii++)
                        {
                            Vector3 pos = Vector3.Lerp(bezier_info.bezier_start.transform.position, bezier_info.bezier_end.transform.position, iii + 1 / (bezier_info.bezier_point_num + 1));
                            points.Add(pos);
                        }
                        // 向points中填充 end 的数据
                        bezier_info.end_idx = points.Count;
                        points.Add(bezier_info.bezier_end.transform.position);
           
                        // 生成控制点
                        bezier_info.bezier_control0 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                        bezier_info.bezier_control0.transform.parent = bezier_control_root.transform;
                        bezier_info.bezier_control0.name = "曲线控制点0";
                        bezier_info.bezier_control0.transform.position = bezier_info.bezier_start.transform.position + new Vector3(0, 0, 2);

                        bezier_info.bezier_control1 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                        bezier_info.bezier_control1.transform.parent = bezier_control_root.transform;
                        bezier_info.bezier_control1.name = "曲线控制点1";
                        bezier_info.bezier_control1.transform.position = bezier_info.bezier_end.transform.position + new Vector3(0, 0, 2);
                        list_bezier_points[ii] = bezier_info;
                        // 将i指向end 下一个
                        i = bezier_info.bezier_end.transform.GetSiblingIndex() + 1;
                    }
                }
                if (!b_insert)
                {
                    points.Add(point.position);
                    i++;
                }
            }
            // 重新生成路点
            render.positionCount = points.Count;
            // 清空原来的路点
            for (int i = map_points.Count - 1; i >= 0; i--)
            {
                GameObject obj = map_points[i];
                DestroyImmediate(obj);
            }
            map_points.Clear();
            for (int i = 0; i < points.Count; i++)
            {
                SetRoadPoint(i, points[i]);
            }
            for (int i = 0; i < list_bezier_points.Count; i++)
            {
                var bezier_info = list_bezier_points[i];
                bezier_info.bezier_start = transform.GetChild(bezier_info.start_idx + 2).gameObject;
                bezier_info.bezier_end = transform.GetChild(bezier_info.end_idx + 2).gameObject;
                list_bezier_points[i] = bezier_info;
            }
        }

        private void EndBezier()
        {
            list_bezier_points.Clear();
            b_bezier_update = false;
            if (bezier_control_root)
            {
                DestroyImmediate(bezier_control_root);
            }
            bezier_control_temp.Clear();
        }

        private void UpdateBezier()
        {
            for (int i = 0; i < list_bezier_points.Count; i++)
            {
                bezier_control_temp.Clear();
                BezierPoints bezier_info = list_bezier_points[i];
                bezier_control_temp.Add(bezier_info.bezier_start.transform.position);
                bezier_control_temp.Add(bezier_info.bezier_control0.transform.position);
                bezier_control_temp.Add(bezier_info.bezier_control1.transform.position);
                bezier_control_temp.Add(bezier_info.bezier_end.transform.position);
                Vector3[] res = GetBezierCurveWithUnlimitPoints(bezier_control_temp.ToArray(), bezier_info.bezier_point_num + 1);
                //循环bezier_point_num遍来绘制贝塞尔曲线每个线段
                for (int ii = 1; ii < res.Length; ii++)
                {
                    //把每条线段绘制出来 完成白塞尔曲线的绘制
                    int idx = bezier_info.start_idx + ii;
                    render.SetPosition(idx, res[ii]);
                    map_points[idx].transform.position = res[ii];
                }
            }
        }

        //传入顶点集合，得到高阶的贝塞尔曲线，顶点数量不限
        //vertexCount 为构建曲线的顶点数，此数值越大曲线越平滑

        public Vector3[] GetBezierCurveWithUnlimitPoints(Vector3[] vertex, int vertexCount)
        {
            List<Vector3> pointList = new List<Vector3>();
            pointList.Clear();
            for (float ratio = 0; ratio <= 1; ratio += 1.0f / vertexCount)
            {
                pointList.Add(UnlimitBezierCurve(vertex, ratio));
            }

            return pointList.ToArray();
        }

        public Vector3 UnlimitBezierCurve(Vector3[] vecs, float t)
        {
            Vector3[] temp = new Vector3[vecs.Length];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = vecs[i];
            }
            //顶点集合有多长，曲线的每一个点就需要计算多少次。

            int n = temp.Length - 1;
            for (int i = 0; i < n; i++)
            {
                //依次计算各两个相邻的顶点的插值，并保存，每次计算都会进行降阶。剩余多少阶计算多少次。直到得到最后一条线性曲线。

                for (int j = 0; j < n - i; j++)
                {
                    temp[j] = Vector3.Lerp(temp[j], temp[j + 1], t);
                }
            }
            //返回当前比例下曲线的点
            return temp[0];
        }


        #endregion

        private void Update()
        {
            if (b_road_select && broad)
            {
                Vector3 dis = obj_center.transform.position - v3_last_pos;
                if (dis.magnitude > 0.1f)
                {
                    RoadMove(dis);
                }

                float a = obj_center.transform.eulerAngles.y;
                if (f_last_angle != a)
                {
                    float dis_angle = a - f_start_angle;
                    RoadRotate(dis_angle, obj_center.transform.position);
                }

                if (render && broad && m_lastRoadWidth != roadWidth)
                {
                    m_lastRoadWidth = roadWidth;
                    render.startWidth = roadWidth;
                    render.endWidth = roadWidth;
                }
            }

            if (b_bezier_update)
            {
                UpdateBezier();
            }
        }

        private void OnDestroy()
        {
            if (bezier_control_root)
            {
                DestroyImmediate(bezier_control_root);
            }
        }
    }
#endif
}